#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"

#include "clang/Tooling/ASTDiff/ASTDiff.h"
#include "clang/Analysis/AnalysisDeclContext.h"

#include<fstream>
#include<iostream>
#include<cstring>
#include<stdlib.h>
#include<sstream>
#include<fstream>
#include<dirent.h>

using namespace std;
using namespace clang;
using namespace llvm;
//全局变量，基类数组的及其下标、二元组（结构体）数组及其下标
int filesnum=0;
int classnamei=0;
static int len=0,sj=0;
 char **ai=new  char*[100];
struct relationship
{
	char* son;
	char* father;
};
relationship newre[20];

relationship re[100];
static int newrei=0;

void saveClassName(const char* allclassname,int flag);//Visitor中调用保存了类名的方法

class FindNamedClassVisitor : public RecursiveASTVisitor<FindNamedClassVisitor> {
public:

   explicit FindNamedClassVisitor(ASTContext *Context)
    : Context(Context) {}
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
    		 llvm::outs() <<"ClassName:  "<<Declaration->getNameAsString()<<"\n";   //类名称
			const char* chr=(Declaration->getNameAsString()).c_str();
			saveClassName(chr,1);
			       for(clang::CXXRecordDecl::base_class_iterator dit=Declaration->bases_begin();dit!=Declaration->bases_end();dit++)//基类迭代器，类型是Specifier
			  {	   
		       const char* ch=(((dit->getType())->getAsCXXRecordDecl())->getNameAsString()).c_str();
				 cout<<"BaseClassName:  "<<ch<<endl;
				 saveClassName(ch,2);
	
			  }
			 return true;
}

private:
  ASTContext *Context;
};

class FindNamedClassConsumer : public clang::ASTConsumer {
public:
  explicit FindNamedClassConsumer(ASTContext *Context)
    : Visitor(Context) {}

  virtual void HandleTranslationUnit(clang::ASTContext &Context) {
    Visitor.TraverseDecl(Context.getTranslationUnitDecl());
  }
	
	FindNamedClassVisitor& getVisitor()
	{
		return Visitor;
	}
  
private:
  FindNamedClassVisitor Visitor;
};

class FindNamedClassAction : public clang::ASTFrontendAction {
public:
   FindNamedClassConsumer *fncc;

  virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
    clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
		fncc=new FindNamedClassConsumer(&Compiler.getASTContext());
    return std::unique_ptr<clang::ASTConsumer>(fncc );
  }	
};

char **readFileName(const char *folderpath)  //读C++项目文件夹下的文件名称
{
	char *newpath=new char[50];
	strcpy(newpath,folderpath);
	char **namelist;
	DIR *dp;
	struct dirent *dirp;
	int n,i,j;
	namelist=(char **)malloc(20*sizeof(char *));
	for(i=0;i<20;i++)
	{
		namelist[i]=(char *)malloc(256*sizeof(char));
	}
	
	if((dp=opendir(folderpath))==NULL)
	{
		cout<<"can't open folder"<<endl;
	}
	i=0;
	while(((dirp=readdir(dp))!=NULL)&&(n<50))
	{
	
		if(memcmp(".",dirp->d_name,1)==0)
		{
			//忽略.和..文件
		}
		else
		{
			memcpy(namelist[i],dirp->d_name,20);
			strcat(newpath,namelist[i]);
			strcpy(namelist[i],newpath);
			strcpy(newpath,folderpath);
			i++;
			filesnum++;
		}
	}
	closedir(dp);
	return namelist;  //返回保存文件名称的数组
}

void findAST(char **filenames)   //扫描每个文件都需要调用该方法，进入Visitor访问语法节点
{
	int i,j;
	for(i=0;i<filesnum;i++)
	{
		ifstream ifile;
		string s="",sum="";
		ifile.open(filenames[i]);
		if(!ifile.is_open())
		{
			cout<<"error opening file!"<<endl;
			return;
		}
		while(!ifile.eof())
		{
			getline(ifile,s);
			sum=sum+s+"\n";
			cout<<"s: "<<s<<endl;
		}
	
	ifile.close();  
  	int m;
	auto fc=make_unique<FindNamedClassAction>();
	m=clang::tooling::runToolOnCode(move(fc), sum);
	}
}

void saveClassName(const char* allclassname,int flag)  //保存类名的方法
{
	char* pc=new char[100];
	strcpy(pc,allclassname); 

if(flag==1)
{
	 strcpy(ai[classnamei],pc);
}
else
{
}

ofstream outfile; //把类名写入文件
if(!outfile)
{
	cout<<"no file"<<endl;
}
outfile.open("/home/song/llvm-project/record/record.txt",ios::app);
if(flag==1)
outfile<<"1,"<<allclassname<<endl;
else
{
	outfile<<"2,"<<allclassname<<endl;
}
}

char** readBaseClassName()
{
	ifstream inFile("/home/song/llvm-project/record/record.txt",ios::in);
	std::string lineStr;
	char**list1,**list2,**list3;
	int i,j,k,flag=0,n=0,m=0;
	list1=(char **)malloc(100*sizeof(char *));
	for(i=0;i<100;i++)
		list1[i]=(char *)malloc(256*sizeof(char));

	list2=(char **)malloc(30*sizeof(char *));
	for(i=0;i<30;i++)
		list2[i]=(char *)malloc(256*sizeof(char));

		list3=(char **)malloc(30*sizeof(char *));
	for(i=0;i<30;i++)
		list3[i]=(char *)malloc(256*sizeof(char));

      for(i=0;i<100;i++)
          {
          	list1[i]="";
          }
 i=0;
 
	while(getline(inFile,lineStr))  //读文件内容，把类名提取出来（子类和基类的标号不同）
	{
		n++;
		cout<<"linestr:     "<<lineStr<<endl;
		const char *line=lineStr.c_str();
		char *pc=new char[100];
		strcpy(pc,line);
       if(len==0)
     {
     	list1[0]=pc;
     	len++;
     }
     else
     {
     	flag=0;
         for(j=0;j<len;j++)
         {
         	if(strcmp(list1[j],pc)==0)
         		flag=1; //表示该类名已经存过
         }
         if(flag==0)
         {
     		list1[len]=pc;
           len++;
         }
     }
           i++;
}

	inFile.close();

for(i=0;i<n;i++)
{
   if(strcmp(list1[0],list1[i])==0)
   	m++;  //如果有重复就计数
}

for(i=0,sj=0;i<len;i++)
{
	if(list1[i][0]=='1'&&list1[i+1][0]=='2')
	{
		re[sj].son=list1[i];
		re[sj].father=list1[i+1];
		sj++;
		i++;
		i++;
	}

	if(list1[i][0]=='1'&&list1[i+1][0]!='2')
 	{
	}
	if(list1[i][0]=='2')
	{
		re[sj].son=re[sj-1].son;
		re[sj].father=list1[i];
		sj++;
	}
}

for(i=0;i<len;i++)
{
	strcpy(list3[i],list1[i]);
}
return list3;
}
	

int main(int argc, char **argv) 
{
	int i,j;
	string s="";
	char **list2,**list4;
	string sum="";
	const char *filepath="/home/song/llvm-project/test/father.hpp";
	cout<<"文件名："<<filepath<<endl;
	for(classnamei=0;classnamei<20;classnamei++)
	{
		ai[classnamei]=new char[64];
		ai[classnamei]=(char *)malloc(50*sizeof(char));
	}
	classnamei=0;
  
	char **filenames=readFileName(argv[1]);
	for(i=0;i<filesnum;i++)
	{
			cout<<"文件名列表："<<filenames[i]<<endl;
	}
	findAST(filenames);
	
	for(i=0;i<classnamei-1;i++)
	{
		cout<<"Result："<<classnamei<<"  "<<i<<"    "<<ai[i]<<endl;
	}

	list2=readBaseClassName();//从读基类名称方法返回的基类数组

		list4=(char **)malloc(30*sizeof(char *));
	for(i=0;i<30;i++)
		list4[i]=(char *)malloc(256*sizeof(char)); //去掉下标的基类数组

    for(i=0;i<len;i++)
    {
    	for(j=2;j<strlen(list2[i]);j++)
    	{
    		list4[i][j-2]=list2[i][j];
    	}
    	
    }
    	for(i=0;i<len;i++)
		{
			cout<<"list4 "<<list4[i]<<endl;
		}
		
	for(i=0;i<sj;i++)
{
cout<<"re.son "<<re[i].son<<" "<<"  re,father "<<re[i].father<<endl;
}
	
ofstream outfile;
if(!outfile)
{
	cout<<"no file"<<endl;
}
outfile.open("/home/song/llvm-project/record/record.txt",ios::app);
outfile<<endl;

	return 0;
}